<template>
  <div>
    <div class="tools-editor-box">
      <Toolbar
        id="toolbar-container"
        ref="refToolbar"
        style="border-bottom: 1px solid #ccc"
        :editor="editor"
        :defaultConfig="toolbarConfig"
      />
      <Editor
        class="editor-container"
        v-model="html"
        style="height: 400px"
        :defaultConfig="editorConfig"
        @onChange="onChange"
        @onCreated="onCreated"
        @customPaste="customPaste"
      />
    </div>
  </div>
</template>
<script>
// api
import { methodPostApi } from "@/api/publicApi";
// 组件
import { Editor, Toolbar } from '@wangeditor/editor-for-vue'
import { createToolbar } from '@wangeditor/editor'
// --------------------------------------------------------
export default {
  name: 'wangEitor',
  components: { Editor, Toolbar },
  props: {
    readOnlyBool:{
      type: Boolean,
      default:()=> false,
    },
    excludeKeys: {
      type: Array,
      default: () => [
        "italic", // 斜体
        'blockquote', // 引用
        // 'fontSize', // 默认字号
        'fontFamily',// 默认字体 在小程序不生效所以 去掉
        // 'lineHeight',// 默认行高
        'bulletedList', // 无序列表
        // 'numberedList', // 有序列表
        'todo', // 待办
        'emotion', // 表情
        'insertLink', // 插入链接
        // 'group-image', // 上传图片
        // {
        // 	key: 'group-image',
        // 	title: '图片',
        // 	iconSvg:
        // 			'<svg viewBox="0 0 1024 1024"><path d="M959.877 128…l224.01-384 256 320h64l224.01-192z"></path></svg>',
        // 	menuKeys: Array(2)
        // },
        // 'video',
        'group-video', // 上传视频
        {
          key: 'group-video',
          title: '插入视频',
          iconSvg:
              '<svg viewBox="0 0 1024 1024"><path d="M981.184 160….904zM384 704V320l320 192-320 192z"></path></svg>',
          menuKeys: Array(2)
        },
        'insertVideo',
        'uploadVideo',
        // 'group-indent',
        'group-more-style',
        'insertTable',
        'codeBlock' // 代码块
      ]
    }
  },

  data() {
    return {
      editor: {},
      html: undefined,
      toolbarConfig: {
        // 排除不需要的菜单项
        excludeKeys: []
      },
      editorConfig: {
        // 富文本内容长度限制
        maxLength: 20000,
        placeholder: '请输入...',
        EXTEND_CONF: {
          mentionConfig: {
            showModal: this.showMentionModal
          }
        },
        // 上传图片配置
        MENU_CONF: {
          uploadImage: {
            // 自定义头
            headers: {
              'x-auth-token': this.$store.state.user.token
            },
            fieldName: 'file',
            // 跨域是否传递 cookie ，默认为 false
            withCredentials: true,
            // 最多可上传几个文件，默认为 100
            maxNumberOfFiles: 3,
            // 自定义上传图片
            customUpload(res, insertFn) {
              const data = new FormData()
              data.append('file', res)
              data.append('businessType', '/portal')
              data.append('fileSize', res.size)
              data.append('fileType', res.type)
              data.append('fileName', encodeURI(res.name))
              methodPostApi('/sys/annex/handleFileUpload', data).then(res => {
                insertFn(res.data.annexPath, '', res.data.annexPath)
              })
            },
            // 自定义插入图片 方法
            customInsert: this.insertImg,
            // 上传之前触发
            onBeforeUpload(file) {
              return file
            }
          }
        }
      }
    }
  },
  methods: {
    /**
    * @Description: 获取HTML文本格式,返回给调用的父组件
    * @author 潘慧敏
    * @date 2022-06-29
    */
    getHtml() {
      const isEmpty = this.editor.isEmpty()
      const isText = this.editor.getText()
      if (isEmpty === false || isText !== '') {
        return this.html
      } else {
        return undefined
      }
    },
    // 上传错误，或者触发 timeout 超时
    onError(file, err, res) {
      console.log(`${file.name} 上传出错`, err, res)
    },
    /**
     * 初始化富文本编辑器
     * 【注意】一定要用 Object.seal() 否则会报错
     */
    onCreated(editor) {
      this.editor = Object.seal(editor)
      // 创建菜单栏
      // eslint-disable-next-line no-unused-vars
			this.toolbarConfig.excludeKeys = this.excludeKeys
      const toolbar = createToolbar({
        editor: this.editor,
        selector: '#toolbar-container',
        config: this.toolbarConfig,
        mode: 'default'
      })
      if(this.readOnlyBool){
        this.editor.disable()
        this.editor.isDisabled()
      }
      // console.log(toolbar.getConfig().toolbarKeys, '获取菜单组')
      // console.log(this.editor.getAllMenuKeys(), '获取全部菜单key')
    },
    onChange(editor) {
      this.curHtml = editor.getHtml()
    },


    //重点来了： 自定义粘贴。可阻止编辑器的默认粘贴，实现自己的粘贴逻辑。(可以实现复制粘贴 word ，有图片)
    customPaste(editor, event, callback) {
      // console.log("ClipboardEvent 粘贴事件对象", event);
      let html = event.clipboardData.getData("text/html"); // 获取粘贴的 html
      // let text = event.clipboardData.getData('text/plain') // 获取粘贴的纯文本
      let rtf = event.clipboardData.getData("text/rtf"); // 获取 rtf 数据（如从 word wsp 复制粘贴）
      var that = this;
      if (html && rtf) {

        // 列表缩进会超出边框，直接过滤掉
        html = html.replace(/text\-indent:\-(.*?)pt/gi, "");

        // 从html内容中查找粘贴内容中是否有图片元素，并返回img标签的属性src值的集合
        const imgSrcs = that.findAllImgSrcsFromHtml(html);

        // 如果有
        if (imgSrcs && Array.isArray(imgSrcs) && imgSrcs.length) {
          // 从rtf内容中查找图片数据
          const rtfImageData = that.extractImageDataFromRtf(rtf);

          // 如果找到
          if (rtfImageData.length) {
            // TODO：此处可以将图片上传到自己的服务器上

            // 执行替换：将html内容中的img标签的src替换成ref中的图片数据，如果上面上传了则为图片路径
            html = that.replaceImagesFileSourceWithInlineRepresentation(
                html,
                imgSrcs,
                rtfImageData
            );
            editor.dangerouslyInsertHtml(html);
          }
        }

        // 阻止默认的粘贴行为
        event.preventDefault();
        return false;
      } else {
        return true;
      }
    },

    // 自定义插入图片
    insertImg(file) {
      console.log(file);
    },

    /**
     * 从html代码中匹配返回图片标签img的属性src的值的集合
     * @param htmlData
     * @return Array
     */
    findAllImgSrcsFromHtml(htmlData) {
      let imgReg = /<img.*?(?:>|\/>)/gi; //匹配图片中的img标签
      let srcReg = /src=[\'\"]?([^\'\"]*)[\'\"]?/i; // 匹配图片中的src

      let arr = htmlData.match(imgReg); //筛选出所有的img
      if (!arr || (Array.isArray(arr) && !arr.length)) {
        return false;
      }

      let srcArr = [];
      for (let i = 0; i < arr.length; i++) {
        let src = arr[i].match(srcReg);
        // 获取图片地址
        srcArr.push(src[1]);
      }

      return srcArr;
    },
    /**
     * 从rtf内容中匹配返回图片数据的集合
     * @param rtfData
     * @return Array
     */
    extractImageDataFromRtf(rtfData) {
      if (!rtfData) {
        return [];
      }

      const regexPictureHeader =
          /{\\pict[\s\S]+?({\\\*\\blipuid\s?[\da-fA-F]+)[\s}]*/;
      const regexPicture = new RegExp(
          "(?:(" + regexPictureHeader.source + "))([\\da-fA-F\\s]+)\\}",
          "g"
      );
      const images = rtfData.match(regexPicture);
      const result = [];

      if (images) {
        for (const image of images) {
          let imageType = false;

          if (image.includes("\\pngblip")) {
            imageType = "image/png";
          } else if (image.includes("\\jpegblip")) {
            imageType = "image/jpeg";
          }

          if (imageType) {
            result.push({
              hex: image
                  .replace(regexPictureHeader, "")
                  .replace(/[^\da-fA-F]/g, ""),
              type: imageType,
            });
          }
        }
      }

      return result;
    },
    /**
     * 将html内容中img标签的属性值替换
     * @param htmlData html内容
     * @param imageSrcs html中img的属性src的值的集合
     * @param imagesHexSources rtf中图片数据的集合，与html内容中的img标签对应
     * @param isBase64Data 是否是Base64的图片数据
     * @return String
     */
    replaceImagesFileSourceWithInlineRepresentation(
        htmlData,
        imageSrcs,
        imagesHexSources,
        isBase64Data = true
    ) {
      if (imageSrcs.length === imagesHexSources.length) {
        for (let i = 0; i < imageSrcs.length; i++) {
          const newSrc = isBase64Data
              ? `data:${
                  imagesHexSources[i].type
              };base64,${this._convertHexToBase64(imagesHexSources[i].hex)}`
              : imagesHexSources[i];

          htmlData = htmlData.replace(imageSrcs[i], newSrc);
        }
      }

      return htmlData;
    },

    /**
     * 十六进制转base64
     */
    _convertHexToBase64(hexString) {
      return btoa(
          hexString
              .match(/\w{2}/g)
              .map((char) => {
                return String.fromCharCode(parseInt(char, 16));
              })
              .join("")
      );
    }
  },
  /**
   * 销毁富文本编辑器
   */
  beforeDestroy() {
    const editor = this.editor
    if (editor == null) return
    editor.destroy() // 组件销毁时，及时销毁 editor ，重要！！！
  }
}
</script>

<style src="@wangeditor/editor/dist/css/style.css"></style>
<style scoped>
.tools-editor-box {
  border: 1px solid #ccc;
}
</style>
